package com.atguigu.springcloud.extend;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.RedisSerializer;

import java.nio.charset.StandardCharsets;
import java.util.Collections;

/**
 * @description: 覆盖原生类  （强转hash键为string）
 * @return
 */
public class StringRedisTemplate extends RedisTemplate<String, Object> {


    @Override
    public HashOperations<String, String, Object> opsForHash() {
        return super.opsForHash();
    }

    //LUA脚本保证原子性
    private static DefaultRedisScript<Long> locklua = new DefaultRedisScript<Long>("if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end", Long.class);


    /**
     * @param key   键
     * @param value 值  一般是uuid
     * @param time  超时时间
     * @return
     * @description: 获得锁 原子操作
     * 存在，返回false，设置失败
     * 不存在，返回 true， 设置成功
     */
    public boolean setNx(String key, Object value, long time) {
        //RedisCallback：扫描调用的回调接口  execute用于处理对象，opsForValue处理字符串
        return execute((RedisCallback<Boolean>) connection -> {
            //转化为原始的RedisSerializer类型即可
            RedisSerializer valueSerializer = getValueSerializer();
            RedisSerializer keySerializer = getKeySerializer();
            Object obj = connection.execute("set", keySerializer.serialize(key), valueSerializer.serialize(value),
                    "NX".getBytes(StandardCharsets.UTF_8), "EX".getBytes(StandardCharsets.UTF_8),
                    String.valueOf(time).getBytes(StandardCharsets.UTF_8));
            return obj != null;
        });

//        redisTemplate.opsForValue().setIfAbsent()获得锁 底层也是用到了execute
    }


    /**
     * @param key   键
     * @param value 值  一般是uuid
     * @return
     * @description: 解锁
     */
    public boolean removeNx(String key, Object value) {
        Long execute = execute(locklua, Collections.singletonList(key), value);
        return execute != null && execute > 0;
    }
}
